home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / smtplib.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2008-10-13  |  14.6 KB  |  574 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. import socket
  5. import re
  6. import email.Utils as email
  7. import base64
  8. import hmac
  9. from email.base64MIME import encode as encode_base64
  10. from sys import stderr
  11. __all__ = [
  12.     'SMTPException',
  13.     'SMTPServerDisconnected',
  14.     'SMTPResponseException',
  15.     'SMTPSenderRefused',
  16.     'SMTPRecipientsRefused',
  17.     'SMTPDataError',
  18.     'SMTPConnectError',
  19.     'SMTPHeloError',
  20.     'SMTPAuthenticationError',
  21.     'quoteaddr',
  22.     'quotedata',
  23.     'SMTP']
  24. SMTP_PORT = 25
  25. CRLF = '\r\n'
  26. OLDSTYLE_AUTH = re.compile('auth=(.*)', re.I)
  27.  
  28. class SMTPException(Exception):
  29.     pass
  30.  
  31.  
  32. class SMTPServerDisconnected(SMTPException):
  33.     pass
  34.  
  35.  
  36. class SMTPResponseException(SMTPException):
  37.     
  38.     def __init__(self, code, msg):
  39.         self.smtp_code = code
  40.         self.smtp_error = msg
  41.         self.args = (code, msg)
  42.  
  43.  
  44.  
  45. class SMTPSenderRefused(SMTPResponseException):
  46.     
  47.     def __init__(self, code, msg, sender):
  48.         self.smtp_code = code
  49.         self.smtp_error = msg
  50.         self.sender = sender
  51.         self.args = (code, msg, sender)
  52.  
  53.  
  54.  
  55. class SMTPRecipientsRefused(SMTPException):
  56.     
  57.     def __init__(self, recipients):
  58.         self.recipients = recipients
  59.         self.args = (recipients,)
  60.  
  61.  
  62.  
  63. class SMTPDataError(SMTPResponseException):
  64.     pass
  65.  
  66.  
  67. class SMTPConnectError(SMTPResponseException):
  68.     pass
  69.  
  70.  
  71. class SMTPHeloError(SMTPResponseException):
  72.     pass
  73.  
  74.  
  75. class SMTPAuthenticationError(SMTPResponseException):
  76.     pass
  77.  
  78.  
  79. class SSLFakeSocket:
  80.     
  81.     def __init__(self, realsock, sslobj):
  82.         self.realsock = realsock
  83.         self.sslobj = sslobj
  84.  
  85.     
  86.     def send(self, str):
  87.         self.sslobj.write(str)
  88.         return len(str)
  89.  
  90.     sendall = send
  91.     
  92.     def close(self):
  93.         self.realsock.close()
  94.  
  95.  
  96.  
  97. class SSLFakeFile:
  98.     
  99.     def __init__(self, sslobj):
  100.         self.sslobj = sslobj
  101.  
  102.     
  103.     def readline(self):
  104.         str = ''
  105.         chr = None
  106.         while chr != '\n':
  107.             chr = self.sslobj.read(1)
  108.             str += chr
  109.         return str
  110.  
  111.     
  112.     def close(self):
  113.         pass
  114.  
  115.  
  116.  
  117. def quoteaddr(addr):
  118.     m = (None, None)
  119.     
  120.     try:
  121.         m = email.Utils.parseaddr(addr)[1]
  122.     except AttributeError:
  123.         pass
  124.  
  125.     if m == (None, None):
  126.         return '<%s>' % addr
  127.     elif m is None:
  128.         return '<>'
  129.     else:
  130.         return '<%s>' % m
  131.  
  132.  
  133. def quotedata(data):
  134.     return re.sub('(?m)^\\.', '..', re.sub('(?:\\r\\n|\\n|\\r(?!\\n))', CRLF, data))
  135.  
  136.  
  137. class SMTP:
  138.     debuglevel = 0
  139.     file = None
  140.     helo_resp = None
  141.     ehlo_resp = None
  142.     does_esmtp = 0
  143.     
  144.     def __init__(self, host = '', port = 0, local_hostname = None):
  145.         self.esmtp_features = { }
  146.         if host:
  147.             (code, msg) = self.connect(host, port)
  148.             if code != 220:
  149.                 raise SMTPConnectError(code, msg)
  150.             
  151.         
  152.         if local_hostname is not None:
  153.             self.local_hostname = local_hostname
  154.         else:
  155.             fqdn = socket.getfqdn()
  156.             if '.' in fqdn:
  157.                 self.local_hostname = fqdn
  158.             else:
  159.                 addr = '127.0.0.1'
  160.                 
  161.                 try:
  162.                     addr = socket.gethostbyname(socket.gethostname())
  163.                 except socket.gaierror:
  164.                     pass
  165.  
  166.                 self.local_hostname = '[%s]' % addr
  167.  
  168.     
  169.     def set_debuglevel(self, debuglevel):
  170.         self.debuglevel = debuglevel
  171.  
  172.     
  173.     def connect(self, host = 'localhost', port = 0):
  174.         if not port and host.find(':') == host.rfind(':'):
  175.             i = host.rfind(':')
  176.             if i >= 0:
  177.                 host = host[:i]
  178.                 port = host[i + 1:]
  179.                 
  180.                 try:
  181.                     port = int(port)
  182.                 except ValueError:
  183.                     raise socket.error, 'nonnumeric port'
  184.                 except:
  185.                     None<EXCEPTION MATCH>ValueError
  186.                 
  187.  
  188.             None<EXCEPTION MATCH>ValueError
  189.         
  190.         if not port:
  191.             port = SMTP_PORT
  192.         
  193.         if self.debuglevel > 0:
  194.             print >>stderr, 'connect:', (host, port)
  195.         
  196.         msg = 'getaddrinfo returns an empty list'
  197.         self.sock = None
  198.         for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
  199.             (af, socktype, proto, canonname, sa) = res
  200.             
  201.             try:
  202.                 self.sock = socket.socket(af, socktype, proto)
  203.                 if self.debuglevel > 0:
  204.                     print >>stderr, 'connect:', sa
  205.                 
  206.                 self.sock.connect(sa)
  207.             except socket.error:
  208.                 msg = None
  209.                 if self.debuglevel > 0:
  210.                     print >>stderr, 'connect fail:', msg
  211.                 
  212.                 if self.sock:
  213.                     self.sock.close()
  214.                 
  215.                 self.sock = None
  216.                 continue
  217.  
  218.         
  219.         if not self.sock:
  220.             raise socket.error, msg
  221.         
  222.         (code, msg) = self.getreply()
  223.         if self.debuglevel > 0:
  224.             print >>stderr, 'connect:', msg
  225.         
  226.         return (code, msg)
  227.  
  228.     
  229.     def send(self, str):
  230.         if self.debuglevel > 0:
  231.             print >>stderr, 'send:', repr(str)
  232.         
  233.         if self.sock:
  234.             
  235.             try:
  236.                 self.sock.sendall(str)
  237.             except socket.error:
  238.                 self.close()
  239.                 raise SMTPServerDisconnected('Server not connected')
  240.             except:
  241.                 None<EXCEPTION MATCH>socket.error
  242.             
  243.  
  244.         None<EXCEPTION MATCH>socket.error
  245.         raise SMTPServerDisconnected('please run connect() first')
  246.  
  247.     
  248.     def putcmd(self, cmd, args = ''):
  249.         if args == '':
  250.             str = '%s%s' % (cmd, CRLF)
  251.         else:
  252.             str = '%s %s%s' % (cmd, args, CRLF)
  253.         self.send(str)
  254.  
  255.     
  256.     def getreply(self):
  257.         resp = []
  258.         if self.file is None:
  259.             self.file = self.sock.makefile('rb')
  260.         
  261.         while None:
  262.             line = self.file.readline()
  263.             if line == '':
  264.                 self.close()
  265.                 raise SMTPServerDisconnected('Connection unexpectedly closed')
  266.             
  267.             if self.debuglevel > 0:
  268.                 print >>stderr, 'reply:', repr(line)
  269.             
  270.             code = line[:3]
  271.             
  272.             try:
  273.                 errcode = int(code)
  274.             except ValueError:
  275.                 errcode = -1
  276.                 break
  277.  
  278.             if line[3:4] != '-':
  279.                 break
  280.                 continue
  281.             continue
  282.             errmsg = '\n'.join(resp)
  283.             if self.debuglevel > 0:
  284.                 print >>stderr, 'reply: retcode (%s); Msg: %s' % (errcode, errmsg)
  285.             
  286.         return (errcode, errmsg)
  287.  
  288.     
  289.     def docmd(self, cmd, args = ''):
  290.         self.putcmd(cmd, args)
  291.         return self.getreply()
  292.  
  293.     
  294.     def helo(self, name = ''):
  295.         if not name:
  296.             pass
  297.         self.putcmd('helo', self.local_hostname)
  298.         (code, msg) = self.getreply()
  299.         self.helo_resp = msg
  300.         return (code, msg)
  301.  
  302.     
  303.     def ehlo(self, name = ''):
  304.         self.esmtp_features = { }
  305.         if not name:
  306.             pass
  307.         self.putcmd('ehlo', self.local_hostname)
  308.         (code, msg) = self.getreply()
  309.         if code == -1 and len(msg) == 0:
  310.             self.close()
  311.             raise SMTPServerDisconnected('Server not connected')
  312.         
  313.         self.ehlo_resp = msg
  314.         if code != 250:
  315.             return (code, msg)
  316.         
  317.         self.does_esmtp = 1
  318.         resp = self.ehlo_resp.split('\n')
  319.         del resp[0]
  320.         for each in resp:
  321.             auth_match = OLDSTYLE_AUTH.match(each)
  322.             if auth_match:
  323.                 self.esmtp_features['auth'] = self.esmtp_features.get('auth', '') + ' ' + auth_match.groups(0)[0]
  324.                 continue
  325.             
  326.             m = re.match('(?P<feature>[A-Za-z0-9][A-Za-z0-9\\-]*) ?', each)
  327.             if m:
  328.                 feature = m.group('feature').lower()
  329.                 params = m.string[m.end('feature'):].strip()
  330.                 if feature == 'auth':
  331.                     self.esmtp_features[feature] = self.esmtp_features.get(feature, '') + ' ' + params
  332.                 else:
  333.                     self.esmtp_features[feature] = params
  334.             feature == 'auth'
  335.         
  336.         return (code, msg)
  337.  
  338.     
  339.     def has_extn(self, opt):
  340.         return opt.lower() in self.esmtp_features
  341.  
  342.     
  343.     def help(self, args = ''):
  344.         self.putcmd('help', args)
  345.         return self.getreply()[1]
  346.  
  347.     
  348.     def rset(self):
  349.         return self.docmd('rset')
  350.  
  351.     
  352.     def noop(self):
  353.         return self.docmd('noop')
  354.  
  355.     
  356.     def mail(self, sender, options = []):
  357.         optionlist = ''
  358.         if options and self.does_esmtp:
  359.             optionlist = ' ' + ' '.join(options)
  360.         
  361.         self.putcmd('mail', 'FROM:%s%s' % (quoteaddr(sender), optionlist))
  362.         return self.getreply()
  363.  
  364.     
  365.     def rcpt(self, recip, options = []):
  366.         optionlist = ''
  367.         if options and self.does_esmtp:
  368.             optionlist = ' ' + ' '.join(options)
  369.         
  370.         self.putcmd('rcpt', 'TO:%s%s' % (quoteaddr(recip), optionlist))
  371.         return self.getreply()
  372.  
  373.     
  374.     def data(self, msg):
  375.         self.putcmd('data')
  376.         (code, repl) = self.getreply()
  377.         if self.debuglevel > 0:
  378.             print >>stderr, 'data:', (code, repl)
  379.         
  380.         if code != 354:
  381.             raise SMTPDataError(code, repl)
  382.         else:
  383.             q = quotedata(msg)
  384.             if q[-2:] != CRLF:
  385.                 q = q + CRLF
  386.             
  387.             q = q + '.' + CRLF
  388.             self.send(q)
  389.             (code, msg) = self.getreply()
  390.             if self.debuglevel > 0:
  391.                 print >>stderr, 'data:', (code, msg)
  392.             
  393.             return (code, msg)
  394.  
  395.     
  396.     def verify(self, address):
  397.         self.putcmd('vrfy', quoteaddr(address))
  398.         return self.getreply()
  399.  
  400.     vrfy = verify
  401.     
  402.     def expn(self, address):
  403.         self.putcmd('expn', quoteaddr(address))
  404.         return self.getreply()
  405.  
  406.     
  407.     def login(self, user, password):
  408.         
  409.         def encode_cram_md5(challenge, user, password):
  410.             challenge = base64.decodestring(challenge)
  411.             response = user + ' ' + hmac.HMAC(password, challenge).hexdigest()
  412.             return encode_base64(response, eol = '')
  413.  
  414.         
  415.         def encode_plain(user, password):
  416.             return encode_base64('\x00%s\x00%s' % (user, password), eol = '')
  417.  
  418.         AUTH_PLAIN = 'PLAIN'
  419.         AUTH_CRAM_MD5 = 'CRAM-MD5'
  420.         AUTH_LOGIN = 'LOGIN'
  421.         if self.helo_resp is None and self.ehlo_resp is None:
  422.             if self.ehlo()[0] <= self.ehlo()[0]:
  423.                 pass
  424.             elif not self.ehlo()[0] <= 299:
  425.                 (code, resp) = self.helo()
  426.                 if code <= code:
  427.                     pass
  428.                 elif not code <= 299:
  429.                     raise SMTPHeloError(code, resp)
  430.                 
  431.             
  432.         
  433.         if not self.has_extn('auth'):
  434.             raise SMTPException('SMTP AUTH extension not supported by server.')
  435.         
  436.         authlist = self.esmtp_features['auth'].split()
  437.         preferred_auths = [
  438.             AUTH_CRAM_MD5,
  439.             AUTH_PLAIN,
  440.             AUTH_LOGIN]
  441.         authmethod = None
  442.         for method in preferred_auths:
  443.             if method in authlist:
  444.                 authmethod = method
  445.                 break
  446.                 continue
  447.         
  448.         if authmethod == AUTH_CRAM_MD5:
  449.             (code, resp) = self.docmd('AUTH', AUTH_CRAM_MD5)
  450.             if code == 503:
  451.                 return (code, resp)
  452.             
  453.             (code, resp) = self.docmd(encode_cram_md5(resp, user, password))
  454.         elif authmethod == AUTH_PLAIN:
  455.             (code, resp) = self.docmd('AUTH', AUTH_PLAIN + ' ' + encode_plain(user, password))
  456.         elif authmethod == AUTH_LOGIN:
  457.             (code, resp) = self.docmd('AUTH', '%s %s' % (AUTH_LOGIN, encode_base64(user, eol = '')))
  458.             if code != 334:
  459.                 raise SMTPAuthenticationError(code, resp)
  460.             
  461.             (code, resp) = self.docmd(encode_base64(password, eol = ''))
  462.         elif authmethod is None:
  463.             raise SMTPException('No suitable authentication method found.')
  464.         
  465.         if code not in (235, 503):
  466.             raise SMTPAuthenticationError(code, resp)
  467.         
  468.         return (code, resp)
  469.  
  470.     
  471.     def starttls(self, keyfile = None, certfile = None):
  472.         (resp, reply) = self.docmd('STARTTLS')
  473.         if resp == 220:
  474.             sslobj = socket.ssl(self.sock, keyfile, certfile)
  475.             self.sock = SSLFakeSocket(self.sock, sslobj)
  476.             self.file = SSLFakeFile(sslobj)
  477.             self.helo_resp = None
  478.             self.ehlo_resp = None
  479.             self.esmtp_features = { }
  480.             self.does_esmtp = 0
  481.         
  482.         return (resp, reply)
  483.  
  484.     
  485.     def sendmail(self, from_addr, to_addrs, msg, mail_options = [], rcpt_options = []):
  486.         if self.helo_resp is None and self.ehlo_resp is None:
  487.             if self.ehlo()[0] <= self.ehlo()[0]:
  488.                 pass
  489.             elif not self.ehlo()[0] <= 299:
  490.                 (code, resp) = self.helo()
  491.                 if code <= code:
  492.                     pass
  493.                 elif not code <= 299:
  494.                     raise SMTPHeloError(code, resp)
  495.                 
  496.             
  497.         
  498.         esmtp_opts = []
  499.         if self.does_esmtp:
  500.             if self.has_extn('size'):
  501.                 esmtp_opts.append('size=%d' % len(msg))
  502.             
  503.             for option in mail_options:
  504.                 esmtp_opts.append(option)
  505.             
  506.         
  507.         (code, resp) = self.mail(from_addr, esmtp_opts)
  508.         if code != 250:
  509.             self.rset()
  510.             raise SMTPSenderRefused(code, resp, from_addr)
  511.         
  512.         senderrs = { }
  513.         if isinstance(to_addrs, basestring):
  514.             to_addrs = [
  515.                 to_addrs]
  516.         
  517.         for each in to_addrs:
  518.             (code, resp) = self.rcpt(each, rcpt_options)
  519.             if code != 250 and code != 251:
  520.                 senderrs[each] = (code, resp)
  521.                 continue
  522.         
  523.         if len(senderrs) == len(to_addrs):
  524.             self.rset()
  525.             raise SMTPRecipientsRefused(senderrs)
  526.         
  527.         (code, resp) = self.data(msg)
  528.         if code != 250:
  529.             self.rset()
  530.             raise SMTPDataError(code, resp)
  531.         
  532.         return senderrs
  533.  
  534.     
  535.     def close(self):
  536.         if self.file:
  537.             self.file.close()
  538.         
  539.         self.file = None
  540.         if self.sock:
  541.             self.sock.close()
  542.         
  543.         self.sock = None
  544.  
  545.     
  546.     def quit(self):
  547.         self.docmd('quit')
  548.         self.close()
  549.  
  550.  
  551. if __name__ == '__main__':
  552.     import sys
  553.     
  554.     def prompt(prompt):
  555.         sys.stdout.write(prompt + ': ')
  556.         return sys.stdin.readline().strip()
  557.  
  558.     fromaddr = prompt('From')
  559.     toaddrs = prompt('To').split(',')
  560.     print 'Enter message, end with ^D:'
  561.     msg = ''
  562.     while None:
  563.         line = sys.stdin.readline()
  564.         if not line:
  565.             break
  566.         
  567.         msg = msg + line
  568.         continue
  569.         print 'Message length is %d' % len(msg)
  570.         server = SMTP('localhost')
  571.         server.sendmail(fromaddr, toaddrs, msg)
  572.         server.quit()
  573. __name__ == '__main__'
  574.